package com.lining.orangeservice.service.impl;

import com.lining.orangeservice.common.BusinessException;
import com.lining.orangeservice.common.enums.ErrorCode;
import com.lining.orangeservice.entity.dto.request.LoginRequest;
import com.lining.orangeservice.entity.dto.LoginResponse;
import com.lining.orangeservice.entity.dto.request.RegisterRequest;
import com.lining.orangeservice.entity.po.Permission;
import com.lining.orangeservice.entity.po.Role;
import com.lining.orangeservice.entity.po.User;
import com.lining.orangeservice.mapper.PermissionMapper;
import com.lining.orangeservice.mapper.RoleMapper;
import com.lining.orangeservice.mapper.UserMapper;
import com.lining.orangeservice.service.AuthService;
import com.lining.orangeservice.utils.JwtUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AuthServiceImpl implements AuthService {

    // 认证管理器, 用于处理用户认证
    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private PermissionMapper permissionMapper;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private HttpServletRequest request;

    @Resource
    private UserDetailsService userDetailsService;


    public LoginResponse login(LoginRequest loginRequest) {

        try {
            User user = userMapper.selectByUsername(loginRequest.getUsername());
            if (user == null) {
                log.warn("登录失败,用户不存在, username: {}", loginRequest.getUsername());
                throw new BusinessException(ErrorCode.USER_NOT_EXISTS);
            }
            // 2. 检查用户状态
            if (user.getStatus() == 0) {
                log.warn("登录失败，用户已被禁用: {}", loginRequest.getUsername());
                throw new BusinessException(ErrorCode.USER_DISABLED);
            }

            // 3. 验证密码
            if (!passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
                log.warn("登录失败，密码错误，用户ID: {}", user.getId());
                throw new BusinessException(ErrorCode.PASSWORD_ERROR);
            }

            // 4. Spring Security 认证
            //使用 AuthenticationManager 对用户提供的凭据进行验证,凭证是用户名密码
            //通过 UsernamePasswordAuthenticationToken 封装用户名和密码信息
            //返回认证结果 Authentication 对象
            log.debug("开始Spring Security认证");
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            loginRequest.getUsername(),
                            loginRequest.getPassword()
                    )
            );

            SecurityContextHolder.getContext().setAuthentication(authentication);
            log.debug("Spring Security认证成功");

            // 5. 查询用户角色和权限
            log.debug("开始加载用户角色和权限信息，用户ID: {}", user.getId());
            List<Role> roles = roleMapper.selectRolesByUserId(user.getId());
            List<Permission> permissions = permissionMapper.selectPermissionsByUserId(user.getId());

            user.setRoles(roles);
            user.setPermissions(permissions);
            log.debug("用户角色和权限加载完成，角色数: {}, 权限数: {}", roles.size(), permissions.size());

            // 6. 更新登录信息
            String clientIp = getClientIp();
            userMapper.updateLoginInfo(user.getId(), LocalDateTime.now(), clientIp);
            log.debug("用户登录信息更新完成，IP: {}", clientIp);

            // 7. 生成 JWT
            log.debug("开始生成JWT");
            String token = jwtUtil.generateToken(user.getUsername(), user.getId());
            log.debug("JWT生成完成");

            // 8. 构建返回结果
            LoginResponse response = buildLoginResponse(token, user);
            log.info("用户登录成功，用户名: {}", loginRequest.getUsername());

            return response;
        } catch (BusinessException e) {
            log.error("用户登录失败，用户名: {}", loginRequest.getUsername(), e);
            throw e;
        } catch (BadCredentialsException e) {
            log.error("用户登录失败，用户名: {}", loginRequest.getUsername(), e);
            throw new BusinessException(ErrorCode.PASSWORD_ERROR);
        } catch (Exception e) {
            log.error("登录系统异常,用户名: {}", loginRequest.getUsername(), e);
            throw new BusinessException(ErrorCode.LOGIN_FAILED, "登录系统异常,请稍后再试");
        }

    }


    public void register(RegisterRequest registerRequest) {
        log.info("开始用户注册流程，用户名: {}, 邮箱: {}",
                registerRequest.getUsername(), registerRequest.getEmail());

        try {
            // 1. 检查用户名是否存在
            if (userMapper.countByUsername(registerRequest.getUsername()) > 0) {
                log.warn("注册失败，用户名已存在: {}", registerRequest.getUsername());
                throw new BusinessException(ErrorCode.USERNAME_EXISTS);
            }

            // 2. 检查邮箱是否存在
            if (userMapper.countByEmail(registerRequest.getEmail()) > 0) {
                log.warn("注册失败，邮箱已被注册: {}", registerRequest.getEmail());
                throw new BusinessException(ErrorCode.EMAIL_EXISTS);
            }

            // 3. 创建用户
            User user = new User();
            user.setUsername(registerRequest.getUsername());
            user.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
            user.setNickname(registerRequest.getNickname());
            user.setEmail(registerRequest.getEmail());
            user.setPhone(registerRequest.getPhone());
            user.setStatus(1); // 默认启用
            user.setCreateBy(1L); // 系统创建

            int result = userMapper.insert(user);
            if (result <= 0) {
                log.error("注册失败，数据库插入异常，用户名: {}", registerRequest.getUsername());
                throw new BusinessException(ErrorCode.USER_REGISTER_FAILED);
            }

            log.info("用户注册成功，用户ID: {}, 用户名: {}", user.getId(), user.getUsername());

        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (Exception e) {
            log.error("注册系统异常，用户名: {}, 异常信息: {}", registerRequest.getUsername(), e.getMessage(), e);
            throw new BusinessException(ErrorCode.USER_REGISTER_FAILED, "注册失败，请稍后重试");
        }
    }

    @Override
    public void logout() {
        Authentication authentication
                = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            String name = authentication.getName();
            log.info("用户注销成功，用户名: {}", name);
            SecurityContextHolder.clearContext();
            log.debug("Spring Security上下文已清除");
        }
    }

    @Override
    public LoginResponse refreshToken(String refreshToken) {
        log.info("开始刷新Token");
        try{
            if (jwtUtil.validateToken(refreshToken)) {
                Long userId = jwtUtil.getUserIdFromToken(refreshToken);
                User user = userMapper.selectById(userId);
                if (user == null || user.getStatus() == 0) {
                    log.warn("Token刷新失败，用户不存在或已被禁用，用户ID: {}", userId);
                    throw new BusinessException(ErrorCode.USER_DISABLED);
                }
                //重新加载用户角色权限
                List<Role> roles = roleMapper.selectRolesByUserId(userId);
                List<Permission> permissions = permissionMapper.selectPermissionsByUserId(userId);
                user.setRoles(roles);
                user.setPermissions(permissions);
                String token = jwtUtil.generateToken(user.getUsername(), user.getId());
                log.debug("JWT生成完成");
                return buildLoginResponse(token, user);
            }else {
                log.warn("Token刷新失败，Token无效，Token: {}", refreshToken);
                throw new BusinessException(ErrorCode.TOKEN_INVALID);
            }
        }catch (BusinessException  e){
            throw e;
        }catch (Exception e){
            log.error("Token刷新系统异常，异常信息: {}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.TOKEN_INVALID, "Token刷新失败，请稍后重试");
        }
    }

    @Override
    public User getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication == null){
            return null;
        }

        String name = authentication.getName();

        log.debug("当前用户: {}", name);
        User user = userMapper.selectByUsername(name);

        if (user != null){
            List<Role> roles = roleMapper.selectRolesByUserId(user.getId());
            List<Permission> permissions = permissionMapper.selectPermissionsByUserId(user.getId());
            user.setRoles(roles);
            user.setPermissions(permissions);
        }
        return user;
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp() {
        String ip = request.getHeader("X-Forwarded-For");
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    private LoginResponse buildLoginResponse(String token, User user) {
        LoginResponse response = new LoginResponse();
        response.setToken(token);
        response.setTokenType("Bearer");
        response.setExpiresIn(jwtUtil.getExpirationDateFromToken(token).getTime() - System.currentTimeMillis());

        //用户基本信息
        LoginResponse.UserInfo userInfo = new LoginResponse.UserInfo();
        userInfo.setId(user.getId());
        userInfo.setUsername(user.getUsername());
        userInfo.setNickname(user.getNickname());
        userInfo.setEmail(user.getEmail());
        userInfo.setPhone(user.getPhone());
        userInfo.setAvatar(user.getAvatar());
        List<LoginResponse.RoleInfo> roleInfos = user.getRoles().stream().map(
                role -> {
                    LoginResponse.RoleInfo roleInfo = new LoginResponse.RoleInfo();
                    roleInfo.setId(role.getId());
                    roleInfo.setRoleName(role.getRoleName());
                    roleInfo.setRoleCode(role.getRoleCode());
                    return roleInfo;
                }
        ).collect(Collectors.toList());
        userInfo.setRoles(roleInfos);

        //权限信息
        List<String> permissionCodes = user.getPermissions().stream()
                .map(Permission::getPermCode)
                .collect(Collectors.toList());
        userInfo.setPermissions(permissionCodes);

        //完整的权限树（包括菜单、按钮、接口）
        userInfo.setPermissionTree(buildPermissionTree(user.getPermissions(), 0L));

        return response;
    }

    /**
     * 构建完整的权限树（包括菜单、按钮、接口）
     */
    private List<LoginResponse.MenuInfo> buildPermissionTree(List<Permission> permissions, Long parentId) {
        List<LoginResponse.MenuInfo> result = new ArrayList<>();
        for (Permission permission : permissions) {
            if (permission.getParentId().equals(parentId)) {
                LoginResponse.MenuInfo menuInfo = new LoginResponse.MenuInfo();
                menuInfo.setId(permission.getId());
                menuInfo.setName(permission.getPermName());
                menuInfo.setCode(permission.getPermCode());
                menuInfo.setType(permission.getPermType());
                menuInfo.setPath(permission.getPath());
                menuInfo.setComponent(permission.getComponent());
                menuInfo.setIcon(permission.getIcon());
                menuInfo.setSort(permission.getSort());
                menuInfo.setStatus(permission.getStatus());

                // 递归构建子节点
                List<LoginResponse.MenuInfo> children = buildPermissionTree(permissions, permission.getId());
                menuInfo.setChildren(children);
                
                result.add(menuInfo);
            }
        }
        return result;
    }
}